package cn.uncode.springcloud.starter.security.interceptor;

import java.io.IOException;
import java.net.InetAddress;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.MediaType;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import cn.uncode.springcloud.starter.security.auth.EmbedUser;
import cn.uncode.springcloud.starter.security.registry.AuthorizeHandler;
import cn.uncode.springcloud.starter.security.utils.SecureUtil;
import cn.uncode.springcloud.starter.web.result.ResultCode;
import cn.uncode.springcloud.utils.Utils;
import cn.uncode.springcloud.utils.json.JsonUtil;
import cn.uncode.springcloud.utils.net.WebUtil;
import cn.uncode.springcloud.utils.obj.SpringUtil;
import cn.uncode.springcloud.utils.string.StringPool;
import lombok.extern.slf4j.Slf4j;

/**
 * jwt拦截器校验
 *
 * @author Juny
 */
@Slf4j
public class SecurityInterceptor extends HandlerInterceptorAdapter {
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
		boolean exists = false;
        //SecurityWebAutoConfiguration 处已经将白名单去除
        //若token不为空
        if (!Utils.isEmpty(SecureUtil.getToken())) {
            if (null != SecureUtil.getUser()) {
                //CAS 端才有用户权限相关
                if (SecureUtil.getUser().getUserType().equals(EmbedUser.USER_TYPE_USER)) {
                    exists = true;
                } else if (SecureUtil.getUser().getUserType().equals(EmbedUser.USER_TYPE_OPT)) {
                    String path = request.getRequestURI();
                    for (String pattern : SecureUtil.getUser().getUrls()) {
                        exists = match(pattern, path);
                        if (exists) {
                            break;
                        }
                    }
                }
            }
        }
        //应用认证入口
        if (!exists) {
        	AuthorizeHandler authorizeHandler = SpringUtil.getBean(AuthorizeHandler.class);
        	if(authorizeHandler != null) {
        		exists = authorizeHandler.authHandle(request, response);
        	}
        }
        
        if (!exists) {
            log.warn("签名认证失败，请求接口：{}，请求IP：{}，请求参数：{}", request.getRequestURI(), WebUtil.getIP(request), JsonUtil.toJson(request.getParameterMap()));
            try {
            	response.setCharacterEncoding(StringPool.UTF_8);
            	//兼容老系统 start
                response.setHeader("Content-type", MediaType.APPLICATION_JSON_UTF8_VALUE);
            	response.setHeader("resultCode", "-401");
            	//兼容老系统 end
            	response.sendError(ResultCode.UN_AUTHORIZED.getCode(), "主机["+InetAddress.getLocalHost().getHostAddress()+"]拒绝访问，没有访问权限："+request.getRequestURI());
            } catch (IOException ex) {
                log.error(ex.getMessage());
            }
            return false;
        }else {
        	return true;
        }
    }


    /**
     * 将通配符表达式转化为正则表达式
     * @param path
     * @return
     */
    private static String getRegPath(String path) {
        char[] chars = path.toCharArray();
        int len = chars.length;
        StringBuilder sb = new StringBuilder();
        boolean preX = false;
        for(int i=0;i<len;i++){
            if (chars[i] == '*'){//遇到*字符
                if (preX){//如果是第二次遇到*，则将**替换成.*
                    sb.append(".*");
                    preX = false;
                }else if(i+1 == len){//如果是遇到单星，且单星是最后一个字符，则直接将*转成[^/]*
                    sb.append("[^/]*");
                }else{//否则单星后面还有字符，则不做任何动作，下一把再做动作
                    preX = true;
                    continue;
                }
            }else{//遇到非*字符
                if (preX){//如果上一把是*，则先把上一把的*对应的[^/]*添进来
                    sb.append("[^/]*");
                    preX = false;
                }
                if (chars[i] == '?'){//接着判断当前字符是不是?，是的话替换成.
                    sb.append('.');
                }else{//不是?的话，则就是普通字符，直接添进来
                    sb.append(chars[i]);
                }
            }
        }
        return sb.toString();
    }
    
    /**
     * 通配符模式
     * @param requestPath - 请求地址
     * @param pattern - 模形
     * @return 结果
     */
    private static boolean match(String pattern, String requestPath) {
        String regPath = getRegPath(pattern);
        return Pattern.compile(regPath).matcher(requestPath).matches();
    }

}
